/**
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY. 
 * See the GNU General Public License for more details.
 * 
 * Copyright (C) 2011 CellObject.net
 */
package net.cellobject.javacodeformatter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


import net.cellobject.javacodeformatter.model.FormatterManager;
import net.cellobject.javacodeformatter.model.IFormatterItem;
import net.cellobject.javacodeformatter.util.EditorUtil;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.texteditor.ITextEditor;

public class Formatter {
	private static Formatter formatter;

	public static Formatter getTPFormatter() {
		if (formatter == null) {
			formatter = new Formatter();
		}
		return formatter;
	}


	public void formatFiles(final IWorkbenchPage page, final IFormatterItem[] items) {
		final IWorkspace workspace = ResourcesPlugin.getWorkspace();
		final IWorkspaceRunnable operation = new IWorkspaceRunnable() {
			public void run(final IProgressMonitor monitor) throws CoreException {
				FormatterManager.isInFormatMode = true; //Don't want events to catch change during formatting process
				for (final IFormatterItem item : items) {
					final IFile itemFile = (IFile)item.getAdapter(IFile.class);
					final IFile[] files = workspace.getRoot().findFilesForLocationURI(itemFile.getLocationURI());
					IWorkbench workbench = page.getWorkbenchWindow().getWorkbench();
					IHandlerService handlerService = (IHandlerService)workbench.getService(IHandlerService.class);
					for (IFile file : files) {
						//Don't format derived files and files in traningportal-trunk derived project
						if (!file.isDerived() && !file.getProject().getName().contains("trainingportal")) {
							openFileThenFormatCleanUpClose(page, handlerService, file);
							break;
						}
					}
				}
				FormatterManager.isInFormatMode = false;
			}
		};
		try {
			workspace.run(operation, null);
		} catch (final CoreException e) {
			e.printStackTrace();
		}
	}

	private void openFileThenFormatCleanUpClose(final IWorkbenchPage page, IHandlerService handlerService, IFile file) {
		try {
			EditorUtil.openFileInEditor(page, file);
			//
			if (file.getFileExtension().equalsIgnoreCase("java")) {
				//Format Java files
				handlerService.executeCommand("org.eclipse.jdt.ui.edit.text.java.format", null);
				//handlerService.executeCommand("org.eclipse.jdt.ui.edit.text.java.organize.imports", null);//This causes compilation error after formatting
				handlerService.executeCommand("org.eclipse.jdt.ui.edit.text.java.clean.up", null);
			} 
			//Save and close file	
			((ITextEditor)page.getActiveEditor().getAdapter(ITextEditor.class)).doSave(new NullProgressMonitor()); //Must use (ITextEditor)page.getActiveEditor(), otherwise it won't work
			((ITextEditor)page.getActiveEditor().getAdapter(ITextEditor.class)).close(true);
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	public void copyDirectory(final File sourceLocation, final File targetLocation) throws IOException {
		if (sourceLocation.isDirectory()) {
			if (!targetLocation.exists()) {
				targetLocation.mkdir();
			}
			final String[] children = sourceLocation.list();
			for (final String element : children) {
				copyDirectory(new File(sourceLocation, element), new File(targetLocation, element));
			}
		} else {
			final InputStream in = new FileInputStream(sourceLocation);
			final OutputStream out = new FileOutputStream(targetLocation);
			// Copy the bits from instream to outstream
			final byte[] buf = new byte[1024];
			int len;
			while ( (len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}
			in.close();
			out.close();
		}
	}

}
